<?php
/**
 * Created by PhpStorm.
 * User: chniccs
 * Date: 2019-11-12
 * Time: 15:41
 */

namespace app\helper;


use app\constant\BillConst;
use app\constant\DistriConst;
use app\constant\OrderConst;
use app\constant\RewardConst;
use app\model\AdminActives;
use app\model\AdminDistridetail;
use app\model\AdminOrder;
use app\model\AdminOrderItem;
use app\model\AdminReward;
use app\model\AppUserBill;
use app\model\AppUserWallet;
use app\queue\QueuePub;
use app\queue\QueueTypes;
use app\util\ReturnCode;
use EasyWeChat\Factory;
use EasyWeChat\Kernel\Exceptions\InvalidConfigException;
use Exception;
use think\Db;

class OrderHelper
{
    /**
     * 得到新订单号
     * @return  string
     */
    public static function build_order_no()
    {
        $code = array('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J');
        $osn = $code[intval(date('Y')) - 2018] . strtoupper(dechex(date('m'))) . date('d') . substr(time(), -5) . substr(microtime(), 2, 5) . sprintf('%02d', rand(0, 99));
//         $osn; //H704764673624352
        return $osn;
    }

    /**
     * 发布消息
     * @param $order_id {String} 订单编号
     * @param float|int $delay 延时时间，默认是5分钟
     * @return bool
     */
    public static function pubCloseOrderQueue($order_id, $delay = OrderConst::ORDER_AUTO_CLOSE_TIME)
    {

        $isPushed = QueuePub::later($delay, QueueTypes::CLOSE_ORDER, ['id'=>$order_id]);
        return $isPushed;

    }

    /**
     * 判断订单是否已经支付，并且是未关闭或完成状态
     */
    public static function orderIsPaidAndNormal($data)
    {

        if ($data['pay_status'] === OrderConst::PAY_STATUS_PAID_ONLINE && $data['trade_status'] === OrderConst::ORDER_STATUS_NORMAL) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 发起退款
     * @param $request \think\Request
     * @param $tid
     * @param $uid
     * @return mixed
     */
    public function applyRefund($request,$tid,$uid=null){
        $orderId = $request->param('order_id');
        $type = $request->param('type');
        if (!$orderId) {
            return ['code'=>ReturnCode::EMPTY_PARAMS, 'msg'=>'缺少必要参数'];
        }
        $where = ['tid'=>$tid];
        $where['del'] = 0;
        $where['id'] = $orderId;
        if($uid!=null){
            $where['uid']=$uid;
        }
        $model = AdminOrder::get($where);
        if (!$model) {
            return ['code'=>ReturnCode::FAILED, 'msg'=>'此订单不存在'];
        }
        if ($model->trade_status !== OrderConst::ORDER_STATUS_NORMAL && $model->trade_status !== OrderConst::ORDER_STATUS_EXPIRE) {
            return ['code'=>ReturnCode::FAILED, 'msg'=>'只有正常或过期状态的订单可退款','done'=>false];
        }
        if ($model->pay_status === OrderConst::PAY_STATUS_WAIT_REFUND) {
            return ['code'=>ReturnCode::FAILED, 'msg'=>'当前订单已经发起退款，请不要重复操作'];
        }
        //退到微信原路退回
        if ($type == OrderConst::REFUND_TO_ORIGINAL) {
            $result = WxHelper::getWxPayConfig($tid, $request);
            if ($result['done']) {
                $config = $result['config'];
                $config['notify_url'] = $request->domain() . '/admin/Notify/wxRefundNotify';
                $app = Factory::payment($config);
                try {
                    $active = AdminActives::get($model->goods_id);
                    $refundMoney = (int)(($model->pay_amount * $active->refund_percentage) / 100);
                    if ($refundMoney <= 0) {
                        $refundMoney = $model->pay_amount;
                    }
                    $result = $app->refund->byOutTradeNumber($model->outer_trade_no, $model->id, $model->pay_amount, $refundMoney, [
                        // 可在此处传入其他参数，详细参数见微信支付文档
                        'refund_desc' => '其它',
                        'notify_url' =>$request->domain() . '/admin/Notify/wxRefundNotify'
                    ]);
                    if ($result['return_code'] == 'SUCCESS') {
                        if ($result['result_code'] == 'SUCCESS') {
                            $model->setAttr('pay_status', OrderConst::PAY_STATUS_WAIT_REFUND);
                            $done = $model->allowField(true)->save();
                            if ($done) {
                                return ['code'=>ReturnCode::SUCCESS, 'msg'=>''];
                            }
                        } else {
                            return ['code'=>ReturnCode::FAILED, 'msg'=> '退款失败' . $result['err_code_des']];
                        }

                    } else {
                        return ['code'=>ReturnCode::FAILED, 'msg'=> '退款失败' . $result['return_msg']];
                    }

                } catch (InvalidConfigException $e) {
                }
            }
            return ['code'=>ReturnCode::FAILED, 'msg'=> '退款失败'];
        } else {
            $done = $this->refund($model->id, OrderConst::REFUND_TO_WALLET);
            if ($done) {
                return ['code'=>ReturnCode::SUCCESS, 'msg'=> ''];
            } else {
                return ['code'=>ReturnCode::FAILED, 'msg'=> '退款失败'];
            }
        }
    }

    /**
     * 修改订单为退款状态
     *  * 退款操作流程：
     * 1、发起退款，区分退款类型，如果是退款到余额，则直接增加余额，如果是退到微信，则需要根据支付订单号发起退款
     *    其中退款到微信需要读取退款比例配置中的数据
     * 2、标记为退款中状态
     *  --此方法仅需要执行以下步骤--
     * 3、退款完成标记订单为已退款
     * 4、修改主订单及子订单交易状态为关闭
     * 5、涉及分销的要标识分销为关闭状态
     * 6、涉及佣金的要标识为关闭
     * @param $orderId
     * @param $type 0 微信退款 1退到余额
     * @param null $refundId 退款id，微信退款时有
     * @param null $refundTime 退款时间 微信退款时有
     * @return bool
     */
    public function refund($orderId, $type, $refundId = null, $refundTime = null)
    {
        $orderModel = AdminOrder::get($orderId);
        if ($orderModel) {
            try {
                Db::startTrans();
                // 3标识主订单为退款状态
                $orderModel->setAttr('pay_status', OrderConst::PAY_STATUS_REFUNDED);
                $orderModel->setAttr('trade_status', OrderConst::ORDER_STATUS_CLOSE);
                if ($type == OrderConst::REFUND_TO_ORIGINAL) {
                    $orderModel->setAttr('refund_id', $refundId);
                    $orderModel->setAttr('refund_time', $refundTime);
                } else {
                    $orderModel->setAttr('refund_time', new \DateTime());
                }
                $done = $orderModel->allowField(true)->save();
                if (!$done) {
                    throw new Exception('操作主订单状态失败');
                }
                // 4 修改处理子订单状态
                (new AdminOrderItem())->where(['tid' => $orderModel->tid, 'order_id' => $orderId])->update(['status' => OrderConst::ORDER_ITEM_STATUS_CLOSE]);
                // 5 修改分销
                (new AdminDistridetail())->where(['tid' => $orderModel->tid, 'order_id' => $orderId])->update(['status' => DistriConst::STATUS_CLOSE]);
                // 6 修改佣金
                (new AdminReward())->where(['tid' => $orderModel->tid, 'order_id' => $orderId])->update(['status' => RewardConst::STATUS_CLOSE]);
                // 7 如果有退回余额的要修改余额
                if ($type === OrderConst::REFUND_TO_WALLET || $orderModel->total_amount != $orderModel->pay_amount) {
                    //这里判断的是组合支付中，需要退回余额的部分
                    $updateWalletDone = $this->reStoreUseWallet([
                        'tid' => $orderModel->tid,
                        'uid' => $orderModel->uid,
                        'all_to_wallet' => ($type === OrderConst::REFUND_TO_WALLET),
                        'pay_amount' => $orderModel->pay_amount,
                        'total_amount' => $orderModel->total_amount,
                        'type' => BillConst::TYPE_INCOME,
                        'source' => BillConst::INCOME_TYPE_REFUND,
                        'desc' => '订单退款'
                    ]);
                    if (!$updateWalletDone) {
                        throw new Exception('操作增加明细失败');
                    }
                }
                Db::commit();
                return true;
            } catch (Exception $e) {
                Db::rollback();
            }
        }
        return false;
    }

    /**
     * 这是一个通用的用来订单取消或者退款后恢复订单使用的余额，优惠券等的方法
     * @param $params array 一个数组 数组中包含有 order_id uid tid total_amount订单总额  pay_amount第三方支付金额 all_to_wallet是否全部退到余额（false/true） desc 描述 type收入还是支出 source收入或支出的类型
     * @return bool
     */
    public function reStoreUseWallet($params)
    {
        try {
            Db::startTrans();
            $updateBill = AppUserBill::toSave(
                $params['tid'],
                $params['uid'],
                isset($params['all_to_wallet'])&& $params['all_to_wallet']? $params['total_amount'] : $params['total_amount'] - $params['pay_amount'],
                $params['type'],
                $params['source'],
                $params['desc']);
            $updateWallet = (new AppUserWallet())->updateMoney($params['uid'], $params['tid'], $params['total_amount'] - $params['pay_amount']);
            if (!($updateBill && $updateWallet)) {
                throw new Exception('操作余额失败');
            }
            Db::commit();
            return true;
        } catch (Exception $e) {
            Db::rollback();
        }
        return false;
    }

    /**
     * 组合支付时的处理
     * @param $params array 一个数组 数组中包含有 是否使用余额useBalance uid tid  total_amount订单总额
     * @return integer pay_amount第三方支付金额
     * @throws Exception
     */
    public function dupPayWayOp($params)
    {
        $totalAmount = $params['total_amount'];
        if ($params['useBalance'] == 1) {
            $walletWhere = ['uid' => $params['uid'], 'tid' => $params['tid']];
            $useWallet = AppUserWallet::get($walletWhere);
            $canUseBalance = $useWallet->money;
            $canUseIncome = $useWallet->income;
            $unUseBalance = 0;//未使用的余额
            $unUseIncome = 0;//未使用的佣金
            $payAmount = 0;
            //这里要判断几种情况，余额能全部支付，余额不够，需要使用推广佣金的，推广佣金也不够，还要用微信支付的
            if ($totalAmount > $canUseBalance) {//余额不够
                $inComeUse = $totalAmount - $canUseBalance;
                if ($inComeUse > $canUseIncome) {//推广佣金也不够
                    //计算需要使用微信支付的金额
                    $payAmount = $inComeUse - $canUseIncome;
                    $unUseIncome = 0;
                } else {
                    //推广佣金够
                    $unUseIncome = $canUseIncome - $inComeUse;
                }
            } else {
                //余额能全部支付
                $unUseBalance = $canUseBalance - $totalAmount;
            }
            $updateBill = AppUserBill::toSave(
                $params['tid'],
                $params['uid'],
                $canUseBalance-$unUseBalance+$canUseIncome-$unUseIncome,
                BillConst::TYPE_EXPENDITURE,
                BillConst::COST_TYPE_GOODS,
                '购买商品');
            if (!$updateBill) {
                throw new Exception('操作增加明细失败');
            }
            $useWallet->setAttr('money', $unUseBalance);
            $useWallet->setAttr('income', $unUseIncome);
            $updateWalletDone = $useWallet->allowField(true)->save();
            if (!$updateWalletDone) {
                throw new Exception('更新余额失败');
            }
        } else {
            $payAmount = $totalAmount;
        }
        return $payAmount;
    }
}
